<template>
    <div class="gems-input"
        :class="{ 
            [`gems-input--${type}`] : type,
            [`gems-input--${size}`] : size,
            'is-disabled': disabled,
            'is-prepend': $slots.prepend,
            'is-append': $slots.append,
            'is-prefix': $slots.prefix,
            'is-suffix': $slots.suffix,
            'is-focus': isFocus,
         }"
    >
        <!-- text input -->
        <template v-if="type !== 'textarea'">
            <!-- prepend slot -->
            <div v-if="$slots.prepend" class="gems-input__prepend">
                <slot name="prepend" />
            </div>
            <!-- input -->
             <div class="gems-input__wrapper">
                <!-- prefix slot -->
                <span v-if="$slots.prefix" class="gems-input__prefix">
                    <slot name="prefix" />
                </span>
                <!-- input inner -->
                <input 
                    ref="inputRef"
                    v-model="innerValue" 
                    class="gems-input__inner" 
                    :type="showPassword ? (passwordVisible ? 'text' : 'password') : type" 
                    v-bind="attrs"
                    :disabled="disabled" 
                    :readonly="readonly"
                    :autocomplete="autocomplete"
                    :placeholder="placeholder"
                    :autofocus="autofocus"
                    :form="form"
                    @input="handleInput"
                    @change="handleChange"
                    @focus="handleFocus"
                    @blur="handleBlur"
                />
                <!-- suffix slot -->
                <span v-if="$slots.suffix || showClear || showPasswordArea" class="gems-input__suffix" @click="keepFocus">
                    <slot name="suffix" />
                    <Icon 
                        icon="circle-xmark"
                        v-if="showClear" 
                        class="gems-input__clear" 
                        @click="handleClear" 
                        @mousedown.prevent="NOOP"
                    />
                    <Icon 
                        :icon="passwordVisible ? 'eye' : 'eye-slash'"
                        v-if="showPasswordArea" 
                        class="gems-input__password" 
                        @click="togglePasswordVisible" 
                    />
                </span>
             </div>
             <!-- append slot -->
            <div v-if="$slots.append" class="gems-input__append">
                <slot name="append" />
            </div>
        </template>
        <!-- textarea input -->
        <template v-else>
            <textarea 
                ref="inputRef"
                v-model="innerValue" 
                class="gems-textarea__wrapper" 
                v-bind="attrs"
                :disabled="disabled" 
                :readonly="readonly"
                :autocomplete="autocomplete"
                :placeholder="placeholder"
                :autofocus="autofocus"
                :form="form"
                @input="handleInput"
                @focus="handleFocus"
                @blur="handleBlur"
            />
        </template>
    </div>

</template>

<script setup lang="ts">
import { ref, watch, computed, useAttrs, nextTick, inject } from 'vue'
import type { Ref } from 'vue'
import type { InputProps, InputEmits } from './types';
import Icon from '../Icon/Icon.vue';
import { formItemContextKey } from '../Form/types';

// Form表单项上下文，用于验证表单数据是否符合验证规则
const formItemContext = inject(formItemContextKey, null)
const runValidation = (trigger?: string) => {
    if (props.validateEvent && formItemContext) {
        formItemContext.validate(trigger).catch((e) => console.log(e.errors))
    }
}

defineOptions({
    name: 'GemsInput',
    inheritAttrs: false,
})
const attrs = useAttrs()
const props = withDefaults(defineProps<InputProps>(), {
    type: 'text',
    autocomplete: 'off',
    validateEvent: true
})
const emits = defineEmits<InputEmits>()

const innerValue = ref(props.modelValue)
const handleInput = () => {
    emits('update:modelValue', innerValue.value)
    emits('input', innerValue.value)
    runValidation('input')
}
const handleChange = () => {
    emits('change', innerValue.value)
    runValidation('change')
}
watch(() => props.modelValue, (newVal) => {
    innerValue.value = newVal
})

const isFocus = ref(false)
const handleFocus = (event: FocusEvent) => {
    isFocus.value = true
    emits('focus', event)
}
const handleBlur = (event: FocusEvent) => {
    isFocus.value = false
    emits('blur',  event)
    // 触发表单验证
    runValidation('blur')
}
const keepFocus = async () => {
    nextTick()
    inputRef.value?.focus()
}
// !!转换boolean类型
const showClear = computed(() => isFocus.value && props.clearable && !props.disabled && !! innerValue.value)
const handleClear = () => {
    innerValue.value = ''
    emits('update:modelValue', '')
    emits('clear')
    emits('change', '')
    emits('input', '')
}
// 占位函数，结合@mousedown.prevent使用，防止点击清空按钮时，触发默认行为（触发blur,使得isFocus.value = false，导致clear区域消失）
const NOOP = () => {}

const passwordVisible = ref(false)
const showPasswordArea = computed(() => props.showPassword && !props.disabled && !!innerValue.value)
const togglePasswordVisible = () => {
    passwordVisible.value = !passwordVisible.value
}

const inputRef = ref() as Ref<HTMLInputElement>

defineExpose({
    ref: inputRef,
})

</script>